package org.blade.personal.framework.orm;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.lang.StringUtils;
import org.blade.personal.engine.DdlKeyWord;
import org.blade.personal.framework.components.metadata.TypeMetaData;
import org.blade.personal.framework.dsl.express.Expression;
import org.blade.personal.framework.lifecycle.LifeCycle;
import org.blade.personal.framework.orm.base.Attribute;
import org.springframework.beans.BeanUtils;

/**
 * 抽象类型别名
 * @author ZGF
 *
 * @param <T>
 */
public abstract class AbstractTypeAlias<T> implements EntityAttribute<T>, TypeAlias<T>, LifeCycle {

	/**
	 * 参数类型
	 */
	protected Class<T> typeClass;
	
	/**
	 * 抽象类型别名构造方法
	 */
	public AbstractTypeAlias() {
		this.typeClass = null;
		Class c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.typeClass = (Class<T>) p[0];
		}
	}
	
	/**
	 * 初始化
	 * 
	 * @param metaData
	 */
	public AbstractTypeAlias(TypeMetaData<T> metaData) {
		this();
		
		this.init(metaData);
		//初始化getter、setter 
		this.setter = BeanUtils.findMethodWithMinimalParameters(
				typeClass, "set"+StringUtils.capitalize(attr.getName()));
		this.getter = BeanUtils.findMethodWithMinimalParameters(
				typeClass, "get"+StringUtils.capitalize(attr.getName()));
	}
	
	protected void init(TypeMetaData<T> metaData){
		this.attr = metaData.getAttr();
		this.alias = metaData.getAlise();

		this.clause = metaData.getClause();
		this.sqlAlise = metaData.getSqlAlise();
		
		this.type = metaData.getType();
		this.expr = metaData.getExpr();
	}
	
	
	/**
	 * 属性的拥有者
	 */
	protected EntityAlias<T> owner;
	
	/**
	 * 属性
	 */
	protected Attribute<T> attr;
	
	/**
	 * 子句
	 */
	protected String clause;
	
	/**
	 * 表别名，用来组装select子句， 如： alise.column_name
	 */
	protected String alias;
	
	/**
	 * SQL结果集别名
	 */
	protected String sqlAlise;
	
	/**
	 * setter方法
	 */
	protected Method setter;
	
	/**
	 * getter方法
	 */
	protected Method getter;
	
	/**
	 * 表达式
	 */
	protected Expression expr;
	
	protected String type;

	public String getType() {
		return this.type;
	}
	
	
	public T getVal() {
		return this.attr.getValue();
	}
	
	
	public String getName() {
		return this.attr.getName();
	}
	
	@Override
	public String getFullName() {
		return this.alias + DdlKeyWord.DOT + this.attr.getName();
	}
	
	
	public void setValue(T value){
		this.attr.setValue(value);
	}
	
	
	public String getClause() {
		if(null == this.clause){
			return this.alias + DdlKeyWord.DOT +  this.attr.getName();
		}
		return this.clause;
	}
	
	/**
	 * 操作
	 * @param attr 属性
	 * @param keyWord 关键词
	 * @return
	 */
	protected TypeAlias<T> op(EntityAttribute<T> attr, String keyWord) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName())
				.append(DdlKeyWord.SPACE)
				.append(keyWord).append(attr.getFullName()).toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	protected TypeAlias<T> op(String val, String keyWord) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName())
				.append(DdlKeyWord.SPACE)
				.append(keyWord).append(val).toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	
	public TypeAlias<T> eq(EntityAttribute<T> type) {
		return this.op(type, DdlKeyWord.EQ);
	}

	
	public TypeAlias<T> notEq(EntityAttribute<T> type) {
		return this.op(type, DdlKeyWord.NOT_EQ);
	}

	
	public TypeAlias<T> likeAll(EntityAttribute<String> type) {
		// TODO 防止SQL注入
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'").append(DdlKeyWord.PRECENT_CODE)
				.append(type.getVal()).append(DdlKeyWord.PRECENT_CODE)
				.append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}

	
	public TypeAlias<T> likeSw(EntityAttribute type) {

		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'")
				.append(DdlKeyWord.PRECENT_CODE).append(type.getVal())
				.append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}

	
	public TypeAlias<T> likeEw(EntityAttribute type) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'").append(type.getVal())
				.append(DdlKeyWord.PRECENT_CODE).append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}

	
	public TypeAlias<T> notLike(EntityAttribute<String> type) {
		
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName())
				.append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.NOT_LIKE)
				.append(((EntityAttribute<String>)type).getFullName()).toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}

	
	public TypeAlias<T> lt(EntityAttribute type) {
		return this.op(type, DdlKeyWord.LT);
	}

	
	public TypeAlias<T> gt(EntityAttribute type) {
		return this.op(type, DdlKeyWord.GT);
	}

	
	public TypeAlias<T> as(String type) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName())
				.append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.AS)
				.append(type).toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> gt(T val) {
		return this.op(val.toString(), DdlKeyWord.GT);
	}
	
	
	
	public TypeAlias<T> eq(Object type) {
		
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias)
			.append(DdlKeyWord.DOT)
			.append(attr.getName())
			.append(DdlKeyWord.SPACE)
			.append(DdlKeyWord.EQ)
			.append(type.toString())
			.toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> likeAll(String val) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'").append(DdlKeyWord.PRECENT_CODE)
				.append(val.toString()).append(DdlKeyWord.PRECENT_CODE)
				.append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> likeEw(String val) {
		TypeAlias<T> typeClone = this.clone();
		
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'").append(val.toString())
				.append(DdlKeyWord.PRECENT_CODE).append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> likeSw(String type) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.LIKE).append("'").append(DdlKeyWord.PRECENT_CODE)
				.append(type.toString()).append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> lt(T val) {
		return this.op(val.toString(), DdlKeyWord.LT);
	}
	
	
	public TypeAlias<T> notLike(String type) {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias).append(DdlKeyWord.DOT)
				.append(attr.getName()).append(DdlKeyWord.SPACE)
				.append(DdlKeyWord.NOT_LIKE).append("'")
				.append(type.toString()).append("'").toString();
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	
	public TypeAlias<T> gtoeq(T val) {
		return this.op(val.toString(), DdlKeyWord.GTOEQ);
	}
	
	
	public TypeAlias<T> ltoeq(T val) {
		return this.op(val.toString(), DdlKeyWord.LTOEQ);
	}
	
	
	@Override
	public TypeAlias<T> and(EntityAttribute type) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public TypeAlias<T> and(String experssion) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public TypeAlias<T> or(EntityAttribute type) {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public TypeAlias<T> or(String experssion) {
		// TODO Auto-generated method stub
		return null;
	}
	
	
	@Override
	public TypeAlias<T> max() {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(DdlKeyWord.MAX).append("(").append(this.alias)
			.append(DdlKeyWord.DOT).append(attr.getName())
			.append(")");
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	@Override
	public TypeAlias<T> min() {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(DdlKeyWord.MIN).append("(").append(this.alias)
			.append(DdlKeyWord.DOT).append(attr.getName())
			.append(")");
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	@Override
	public TypeAlias<T> asc() {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias)
			.append(DdlKeyWord.DOT).append(attr.getName())
			.append(DdlKeyWord.SPACE).append(DdlKeyWord.ASC);
		typeClone.setClause(buff.toString());
		return typeClone;
	}
	
	@Override
	public TypeAlias<T> desc() {
		TypeAlias<T> typeClone = this.clone();
		StringBuilder buff = new StringBuilder();
		buff.append(this.alias)
			.append(DdlKeyWord.DOT).append(attr.getName())
			.append(DdlKeyWord.SPACE).append(DdlKeyWord.DESC);
		typeClone.setClause(buff.toString());
		return typeClone;	}
		
	
	public String getTable() {
		return this.attr.getTalbe();
	}
	
	
	public TypeAlias<T> clone() {
		Attribute<T> attr = this.attr.clone();
		TypeAlias newTypeAlies = TypeAliasFactory.newInstance()
				.create(attr, clause, alias, sqlAlise, type, expr);
		EntityAttribute entityAttribute = (EntityAttribute)newTypeAlies;
		entityAttribute.setOwner(this.owner);
		return (TypeAlias)entityAttribute;
	}

	
	public void setClause(String clause){
		this.clause = clause;
	}
	
	
	@Override
	public String getOwner() {
		return this.owner.getEntityName();
	}
	
	@Override
	public void setOwner(EntityAlias owner) {
		this.owner = owner;
	}
	
	@Override
	public void destroy() {
		this.owner = null;
		this.alias = null;
		this.attr = null;
		this.sqlAlise = null;
		this.type = null;
		this.expr = null;
	}
	
	@Override
	public void init() {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public Expression getExpression() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public void setExpression(String express) {
		// TODO Auto-generated method stub
		
	}
	
}
